package preprocessor.absorption;

import java.util.HashMap;
import java.util.Map;

import utils.exception.AbsorptionException;

//import entities.InclusionAxiom;
import entities.concept.AndConcept;
import entities.concept.AtomicConcept;
import entities.concept.Concept;
import entities.concept.Nominal;
import entities.concept.PConcept;

/**
 * Only binary axioms of the form (A and DEF_r)->C is allowed.
 * @author j55wu
 *
 */
public class BinaryAbsorptionGuardedExistentials implements Absorption {
	private Map<AtomicConcept, Map<AtomicConcept, Concept>> specialBinaryEntries;
	private long numEntry;
	
	

	public void resetEntryCount() {
		numEntry = 0;
	}

	public BinaryAbsorptionGuardedExistentials() {
		specialBinaryEntries = new HashMap<AtomicConcept, Map<AtomicConcept, Concept>>();
		numEntry = 0;
	}

	public void clearEntries() {
		specialBinaryEntries.clear();
	}

	public long getNumberOfEntries() {
		return numEntry;
	}

	public Map<AtomicConcept, Map<AtomicConcept, Concept>> getTbLimited() {
		return specialBinaryEntries;
	}

	public boolean absorb() {
		return false;
	}

	public static enum entryOrder {
		Prim_First, Guard_First
	}

	public static entryOrder defOrder = entryOrder.Guard_First;
	

	// entry order type can be null, default used.
	public void addBinaryEntry(PConcept lk, PConcept rk, Concept v) throws AbsorptionException {
		PConcept defr = null;
		PConcept ac = null;
		if(lk.isRoleGuard()){
			defr = lk;
			ac = rk;
		}else if(rk.isRoleGuard()){
			defr = rk;
			ac = rk;
		}else{
			throw new AbsorptionException("Only limited binary absorption supported: A and Guard_role:"+lk+"; "+rk);
		}
		if (defOrder.equals(entryOrder.Prim_First)) {
			addEntry(ac, defr, v);
			return;
		} else if (defOrder.equals(entryOrder.Guard_First)) {
			addEntry(defr, ac, v);
			return;
		} else {
			addEntry(lk, rk, v);
			return;
		}
	}

	// order preserving: lk AND rk ---> v
	private void addEntry(PConcept lk, PConcept rk, Concept v) {
		numEntry++;
		if (v.isTop()) {
			// ignore top
			return;
		}
		Map<AtomicConcept, Concept> im = null;
		if (specialBinaryEntries.containsKey(lk)) {
			im = specialBinaryEntries.get(lk);
		} else {
			im = new HashMap<AtomicConcept, Concept>();
		}
		Concept value = null;
		if (im.containsKey(rk)) {
			value = new AndConcept(v, im.get(rk));
		} else {
			value = v;
		}
		im.put(rk, value);
		specialBinaryEntries.put(lk, im);
	}

//	public void updateEntryValue(AtomicConcept lk, AtomicConcept rk, Concept v,
//			entryOrder t) throws AbsorptionException {
//		if (t == null) {
//			t = defOrder;
//		}
//		Nominal o = null;
//		AtomicConcept ac = null;
//		if (lk instanceof Nominal) {
//			o = (Nominal) lk;
//			ac = rk;
//		} else if (rk instanceof Nominal) {
//			o = (Nominal) rk;
//			ac = lk;
//		} else if (Absorption.BA_Limited) {
//			// only special binary absorption allowed
//			throw new AbsorptionException(
//					"Only limited binary absorption is allowed. "
//							+ "Must have *one nominal* in the keys.");
//		}
//		if (o == null) {
//			return;
//		}
//		if (t.equals(entryOrder.Nominal_First)) {
//			updateEntryValue(o, ac, v);
//			return;
//		} else if (t.equals(entryOrder.Nominal_Second)) {
//			updateEntryValue(ac, o, v);
//			return;
//		} else {
//			updateEntryValue(lk, rk, v);
//			return;
//		}
//	}
	
//	// order preserving: lk AND rk ---> v, use the original order
//	private void updateEntryValue(AtomicConcept lk, AtomicConcept rk, Concept v) {
//		Map<AtomicConcept, Concept> im = null;
//		if (specialBinaryEntries.containsKey(lk)) {
//			im = specialBinaryEntries.get(lk);
//		} else {
//			return;
//		}
//		if (im.containsKey(rk)) {
//			im.put(rk, v);
//		} else {
//			return;
//		}
//		specialBinaryEntries.put(lk, im);
//	}
	
	
	public Concept getEntry(PConcept lk, PConcept rk) {
		PConcept defr = null;
		PConcept ac = null;
		if (lk.isRoleGuard()) {
			defr = lk;
			ac = rk;
		} else if (rk.isRoleGuard()) {
			defr = rk;
			ac = lk;
		} else {
			return null;
		}
		if (defOrder.equals(entryOrder.Prim_First)) {
			if (specialBinaryEntries.containsKey(ac)) {
				Map<AtomicConcept, Concept> im = specialBinaryEntries.get(ac);
				if (im.containsKey(ac)) {
					return im.get(ac);
				}
			}
			return null;
		}
		if (defOrder.equals(entryOrder.Guard_First)) {
			if (specialBinaryEntries.containsKey(defr)) {
				Map<AtomicConcept, Concept> im = specialBinaryEntries.get(defr);
				if (im.containsKey(ac)) {
					return im.get(ac);
				}
			}
			return null;
		}
		return null;
	}

}
